#pragma once

namespace ezstl {

#ifdef __has_builtin
#ifdef __is_identifier
// Intel and older Clang require !__is_identifier for some built-ins:
#define _EZSTL_HAS_BUILTIN(B) (__has_builtin(B) || !__is_identifier(B))
#else
#define _EZSTL_HAS_BUILTIN(B) __has_builtin(B)
#endif
#endif

template <typename T, T V>
struct integer_constant {
  static constexpr T value = V;
  using value_type = T;
  using type = integer_constant<T, V>;
  // Conversion Function non return type
  constexpr operator value_type() const { return value; }
  // C++ >= 14
  constexpr value_type operator()() const { return value; }
};

template <bool V>
using bool_constant = integer_constant<bool, V>;

using true_type = bool_constant<true>;
using false_type = bool_constant<false>;

template <bool, typename T = void>
struct enable_if {};

template <typename T>
struct enable_if<true, T> {
  using type = T;
};

template <bool Cond, typename T>
using enable_if_t = typename enable_if<Cond, T>::type;

template <bool>
struct __conditional {
  // 模板别名
  // template<模板参数列表>
  // using 别名 = 目标类型;
  template <typename T, typename>
  using type = T;
};

template <>
struct __conditional<false> {
  template <typename, typename U>
  using type = U;
};

// typename 待决名 template 待决名

template <bool Cond, typename Ifture, typename Iffalse>
using conditional_t =
    typename __conditional<Cond>::template type<Ifture, Iffalse>;

// type categories
template <typename T>
struct is_void : false_type {};
template <>
struct is_void<void> : true_type {};
template <>
struct is_void<const void> : true_type {};

// type properties
template <typename T>
struct is_const : false_type {};
template <typename T>
struct is_const<const T> : true_type {};
template <typename T>
struct is_pod : false_type {};
template <>
struct is_pod<bool> : true_type {};
template <>
struct is_pod<char> : true_type {};
template <>
struct is_pod<signed char> : true_type {};
template <>
struct is_pod<unsigned char> : true_type {};
template <>
struct is_pod<short> : true_type {};
template <>
struct is_pod<unsigned short> : true_type {};
template <>
struct is_pod<int> : true_type {};
template <>
struct is_pod<unsigned int> : true_type {};
template <>
struct is_pod<long> : true_type {};
template <>
struct is_pod<unsigned long> : true_type {};
template <>
struct is_pod<long long> : true_type {};
template <>
struct is_pod<unsigned long long> : true_type {};
template <>
struct is_pod<float> : true_type {};
template <>
struct is_pod<double> : true_type {};
template <>
struct is_pod<long double> : true_type {};
template <typename T>
struct is_pod<T *> : true_type {};

//
/// remove const
template <typename T>
struct remove_const {
  using type = T;
};
template <typename T>
struct remove_const<T const> {
  using type = T;
};

/// remove volatile
template <typename T>
struct remove_volatile {
  using type = T;
};
template <typename T>
struct remove_volatile<T volatile> {
  using type = T;
};

/// remove const volatile
template <typename _Tp>
struct remove_cv {
  using type = _Tp;
};
template <typename _Tp>
struct remove_cv<const _Tp> {
  using type = _Tp;
};
template <typename _Tp>
struct remove_cv<volatile _Tp> {
  using type = _Tp;
};
template <typename _Tp>
struct remove_cv<const volatile _Tp> {
  using type = _Tp;
};

/// add const
template <typename T>
struct add_const {
  using type = const T;
};
/// add volatile
template <typename T>
struct add_volatile {
  using type = volatile T;
};
/// add const volatile
template<typename T>
struct add_cv {
  using type = const volatile T;
};

// Reference transformations
template <typename T>
struct remove_reference {
  using type = T;
};

template <typename T>
struct remove_reference<T &> {
  using type = T;
};

template<typename T>
struct remove_reference<T &&> {
  using type = T;
};

}  // namespace ezstl